/***********************************************************************/
/*  This file is part of the ARM Toolchain package                     */
/*  Copyright (c) 2020 Keil - An ARM Company. All rights reserved.     */
/***********************************************************************/
/*                                                                     */
/*  FlashPrg.c:  Flash Programming Functions adapted for               */
/*               ST Microelectronics STM32h747I-DISCO Flash            */
/*                                                                     */
/***********************************************************************/

#include "FlashOS.H"
#include "sfud.h"
#include "gpio.h"
#include "spi.h"

#define  PAGE_SIZE 4096
uint8_t  read_buf[PAGE_SIZE]; 
uint32_t base_adr;
extern void SystemClock_Config(void);

/*
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Device Base Address
 *                    clk:  Clock Frequency (Hz)
 *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

#if defined FLASH_MEM || defined FLASH_OTP
int Init (unsigned long adr, unsigned long clk, unsigned long fnc)
{
//    SystemInit();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_SPI1_Init();
    base_adr = adr;

    if(sfud_init() == SFUD_SUCCESS){
        return 0;
    }else{
        return 1;
    }
}
#endif


/*
 *  De-Initialize Flash Programming Functions
 *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

#if defined FLASH_MEM || defined FLASH_OTP
int UnInit (unsigned long fnc)
{

    return (0);
}
#endif

/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseChip (void)
{
    int result = 0;
    const sfud_flash *flash = sfud_get_device_table();
    result = sfud_erase (flash, 0, flash->chip.capacity);
    if (result == SFUD_SUCCESS)
        return 0;
    else
        return result;                                  // Finished without Errors
}

/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

#ifdef FLASH_MEM
int EraseSector (unsigned long adr)
{
    int result = 0;
    uint32_t block_start;
    const sfud_flash *flash;
    flash  = sfud_get_device_table();
    block_start  = adr - base_adr;
    result = sfud_erase (flash, block_start, 4096);
    if (result == SFUD_SUCCESS)
        return 0;
    else
        return result;
}
#endif


/*
 *  Program Page in Flash Memory
 *    Parameter:      adr:  Page Start Address
 *                    sz:   Page Size
 *                    buf:  Page Data
 *    Return Value:   0 - OK,  1 - Failed
 */

#if defined FLASH_MEM 
int ProgramPage (unsigned long block_start, unsigned long size, unsigned char *buffer)
{
    const sfud_flash *flash = sfud_get_device_table() + 0;
    uint32_t start_addr = block_start - base_adr;

    if(sfud_write(flash, start_addr, size, buffer) == SFUD_SUCCESS)
        return 0;
    else
        return 1;
}

int BlankCheck (unsigned long adr, unsigned long sz, unsigned char pat) {
 

  return (0);                           // Memory is blank
}

unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf)
{
    unsigned long i;
    const sfud_flash *flash = sfud_get_device_table();
    uint32_t start_addr = adr - base_adr;
    sfud_read(flash, start_addr, sz, read_buf);
    for (i = 0; i < PAGE_SIZE; i++)
    {
        if (read_buf[i] != buf[i])
        {
            return (adr + i); // Verification Failed (return address)
        }
    }

    return (adr + sz); // Done successfully                 
}

#endif
